/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.thinkinbunny.mymusic;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.Equalizer;
import android.media.audiofx.Visualizer;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

public class AudioFxActivity extends Activity {
	private static final String TAG = "xiawei";

	private static final float VISUALIZER_HEIGHT_DIP = 160f;

	private MediaPlayer mMediaPlayer;
	private Visualizer mVisualizer;
	private Equalizer mEqualizer;

	private LinearLayout mLinearLayout;
	private VisualizerView mVisualizerView;
	private TextView mStatusTextView;
	private TextView mInfoView;

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);

		mStatusTextView = new TextView(this);

		mLinearLayout = new LinearLayout(this);
		mLinearLayout.setOrientation(LinearLayout.VERTICAL);
		mLinearLayout.addView(mStatusTextView);

		setContentView(mLinearLayout);

		// Create the MediaPlayer
		mMediaPlayer = MediaPlayer.create(this, R.raw.breakup);
		Log.d(TAG,
				"MediaPlayer audio session ID: "
						+ mMediaPlayer.getAudioSessionId());

		setupVisualizerFxAndUI();
		Log.i(TAG, "setupVisualizerFxAndUI done");
		setupEqualizerFxAndUI();
		Log.i(TAG, "setupEqualizerFxAndUI done");
		// Make sure the visualizer is enabled only when you actually want to
		// receive data, and
		// when it makes sense to receive data.
		mVisualizer.setEnabled(true);

		// When the stream ends, we don't need to collect any more data. We
		// don't do this in
		// setupVisualizerFxAndUI because we likely want to have more,
		// non-Visualizer related code
		// in this callback.
		mMediaPlayer
				.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
					@Override
					public void onCompletion(MediaPlayer mediaPlayer) {
						mVisualizer.setEnabled(false);
						getWindow().clearFlags(
								WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
						setVolumeControlStream(AudioManager.STREAM_SYSTEM);
						mStatusTextView.setText("音乐播放完毕");
					}
				});

		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		setVolumeControlStream(AudioManager.STREAM_MUSIC);
		mMediaPlayer.start();
		mStatusTextView.setText("播放音乐中....");
	}

	private void setupEqualizerFxAndUI() {
		// Create the Equalizer object (an AudioEffect subclass) and attach it
		// to our media player,
		// with a default priority (0).
		mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
		mEqualizer.setEnabled(true);

		TextView eqTextView = new TextView(this);
		eqTextView.setText("均衡器:");
		mLinearLayout.addView(eqTextView);

		short bands = mEqualizer.getNumberOfBands();

		final short minEQLevel = mEqualizer.getBandLevelRange()[0];
		final short maxEQLevel = mEqualizer.getBandLevelRange()[1];

		for (short i = 0; i < bands; i++) {
			final short band = i;

			TextView freqTextView = new TextView(this);
			freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
					ViewGroup.LayoutParams.FILL_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT));
			freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
			freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000)
					+ " Hz");
			mLinearLayout.addView(freqTextView);

			LinearLayout row = new LinearLayout(this);
			row.setOrientation(LinearLayout.HORIZONTAL);

			TextView minDbTextView = new TextView(this);
			minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
					ViewGroup.LayoutParams.WRAP_CONTENT,
					ViewGroup.LayoutParams.WRAP_CONTENT));
			minDbTextView.setText((minEQLevel / 100) + " dB");

			TextView maxDbTextView = new TextView(this);
			maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
					ViewGroup.LayoutParams.WRAP_CONTENT,
					ViewGroup.LayoutParams.WRAP_CONTENT));
			maxDbTextView.setText((maxEQLevel / 100) + " dB");

			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
					ViewGroup.LayoutParams.FILL_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT);
			layoutParams.weight = 1;
			SeekBar bar = new SeekBar(this);
			bar.setLayoutParams(layoutParams);
			bar.setMax(maxEQLevel - minEQLevel);
			bar.setProgress(mEqualizer.getBandLevel(band));

			bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
				@Override
				public void onProgressChanged(SeekBar seekBar, int progress,
						boolean fromUser) {
					mEqualizer.setBandLevel(band,
							(short) (progress + minEQLevel));
				}

				@Override
				public void onStartTrackingTouch(SeekBar seekBar) {
				}

				@Override
				public void onStopTrackingTouch(SeekBar seekBar) {
				}
			});

			row.addView(minDbTextView);
			row.addView(bar);
			row.addView(maxDbTextView);

			mLinearLayout.addView(row);
		}
	}

	private void setupVisualizerFxAndUI() {
		mVisualizerView = new VisualizerView(this);
		mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.FILL_PARENT,
				(int) (VISUALIZER_HEIGHT_DIP * getResources()
						.getDisplayMetrics().density)));
		mLinearLayout.addView(mVisualizerView);

		mInfoView = new TextView(this);
		String infoStr = "";

		int[] csr = Visualizer.getCaptureSizeRange();
		if (csr != null) {
			String csrStr = "CaptureSizeRange: ";
			for (int i = 0; i < csr.length; i++) {
				csrStr += csr[i];
				csrStr += " ";
			}
			infoStr += csrStr;
		}

		final int maxCR = Visualizer.getMaxCaptureRate();

		infoStr = infoStr + "\nMaxCaptureRate: " + maxCR;

		mInfoView.setText(infoStr);
		mLinearLayout.addView(mInfoView);

		mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
		mVisualizer.setCaptureSize(256);
		mVisualizer.setDataCaptureListener(
				new Visualizer.OnDataCaptureListener() {
					@Override
					public void onWaveFormDataCapture(Visualizer visualizer,
							byte[] bytes, int samplingRate) {
						mVisualizerView.updateVisualizer(bytes);
					}

					@Override
					public void onFftDataCapture(Visualizer visualizer,
							byte[] fft, int samplingRate) {
						mVisualizerView.updateVisualizer(fft);
					}
				}, maxCR / 2, false, true);
	}

	@Override
	protected void onPause() {
		super.onPause();

		if (isFinishing() && mMediaPlayer != null) {
			mVisualizer.release();
			mEqualizer.release();
			mMediaPlayer.release();
			mMediaPlayer = null;
		}
	}

	/**
	 * A simple class that draws waveform data received from a
	 * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
	 */
	class VisualizerView extends View {
		private byte[] mBytes;
		private float[] mPoints;
		private final Rect mRect = new Rect();

		private final Paint mForePaint = new Paint();
		private final int mSpectrumNum = 48;
		private boolean mFirst = true;

		public VisualizerView(Context context) {
			super(context);
			init();
		}

		private void init() {
			mBytes = null;

			mForePaint.setStrokeWidth(8f);
			mForePaint.setAntiAlias(true);
			mForePaint.setColor(Color.rgb(0, 128, 255));
		}

		public void updateVisualizer(byte[] fft) {
			if (mFirst) {
				mInfoView.setText(mInfoView.getText().toString()
						+ "\nCaptureSize: " + fft.length);
				mFirst = false;
			}

			byte[] model = new byte[fft.length / 2 + 1];

			model[0] = (byte) Math.abs(fft[0]);
			for (int i = 2, j = 1; j < mSpectrumNum;) {
				model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
				i += 2;
				j++;
			}
			mBytes = model;
			invalidate();
		}

		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);

			if (mBytes == null) {
				return;
			}

			if (mPoints == null || mPoints.length < mBytes.length * 4) {
				mPoints = new float[mBytes.length * 4];
			}

			mRect.set(0, 0, getWidth(), getHeight());

			// 绘制波形
			// for (int i = 0; i < mBytes.length - 1; i++) {
			// mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
			// mPoints[i * 4 + 1] = mRect.height() / 2
			// + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
			// mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length -
			// 1);
			// mPoints[i * 4 + 3] = mRect.height() / 2
			// + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
			// }

			// 绘制频谱
			final int baseX = mRect.width() / mSpectrumNum;
			final int height = mRect.height();

			for (int i = 0; i < mSpectrumNum; i++) {
				if (mBytes[i] < 0) {
					mBytes[i] = 127;
				}

				final int xi = baseX * i + baseX / 2;

				mPoints[i * 4] = xi;
				mPoints[i * 4 + 1] = height;

				mPoints[i * 4 + 2] = xi;
				mPoints[i * 4 + 3] = height - mBytes[i];
			}

			canvas.drawLines(mPoints, mForePaint);
		}
	}
}
